package p.ithorns.framework.redis.stream.mapper;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.hash.ObjectHashMapper;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Map;

/**
 * RedisJsonHashMapper
 *
 * @author Ht.L
 * @date 2023-07-06 11:26
 * @since 1.0.0
 */
public class RedisJsonHashMapper extends ObjectHashMapper {

    private final static Logger log = LoggerFactory.getLogger(RedisJsonHashMapper.class);

    private final static ObjectMapper OM;

    static {
        OM = JsonMapper.builder()
                .defaultDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss[.SSS]"))
                .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
                .enable(JsonGenerator.Feature.IGNORE_UNKNOWN)
                .enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN)
                .enable(JsonReadFeature.ALLOW_MISSING_VALUES)
                // 不忽略大小写 针对‘bKey’这样的属性以免会被过滤
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .build();
    }

    @Override
    public Map<byte[], byte[]> toHash(Object source) {
        if (source instanceof String) {
            return super.toHash(source);
        }

        String json = toJson(source);
        return super.toHash(json);
    }

    @Override
    public Object fromHash(Map<byte[], byte[]> hash) {
        return super.fromHash(hash);
    }

    @Override
    public <T> T fromHash(Map<byte[], byte[]> hash, Class<T> type) {
        String o = (String) super.fromHash(hash);
        return fromJson(o, type);
    }

    /**
     * Bean -> Json
     */
    private String toJson(Object object) {
        try {
            return OM.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            log.warn("Failed convert Object to Json string.", e);
        }
        return null;
    }

    /**
     * Json -> Bean
     */
    private <T> T fromJson(String json, Class<T> clazz) {
        try {
            return OM.readValue(json, clazz);
        } catch (IOException e) {
            log.warn(e.getMessage());
        }
        return null;
    }

}